#include "Steganography.h"

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Steganography
 *      Method:  hide
 * Description:  Esconde uma mensagem na imagem passada
 *--------------------------------------------------------------------------------------
 */
void Steganography::hide(Image &image, istream &msg, Key &key)
{
    // Cria tabela de transposição
    TransTable trans(msg);

    // Recupera a quantidade de armazenamento da imagem
    uint storage = (image.cols * image.rows * image.channels() * key.nbits) / 8;

    // Se o tamanho da mensagem for maior que o armazenameto, gera exeção
    if(trans.size > storage)
        throw MessageTooBigException(storage, trans.size);

    uchar* data = image.data;
    uint count = 0;

    // Quantidade de pixels necessárias para armazenar 1 byte
    uint inc = 8 / key.nbits;
    // Valor binário para selecionar só a região de interesse
    uint ch = (uint) pow(2, key.nbits) - 1;

    // Preenche a imagem com os bits da mensagem
    for(uint i = 0; i < KEY_SIZE; i++)
        for(char m : trans.table[key.position[i]])
        {
            // Utiliza alguns pixels para armazenar um byte da mensagem
            uint s = 8-key.nbits;
            for(uint k = 0; k < inc; k++)
            {
                data[count] = (data[count] & (255-ch)) | ((m >> s) & ch);
                s -= key.nbits;
                count++;
            }
        }

    // Preenche o restante da imagem com 0s nos bits menos significantes
    for( ; count < image.step*image.rows; count++)
        data[count] = data[count] & (255-ch);
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Steganography
 *      Method:  extract
 * Description:  Extrai uma mensagem da imagem passada
 *--------------------------------------------------------------------------------------
 */
void Steganography::extract(Image &image, ostream &msg, Key &key)
{
    string text;
    uchar* data = image.data;

    // Quantidade de pixels necessárias para armazenar 1 byte
    uint inc = 8 / key.nbits;
    // Valor binário para selecionar só a região de interesse
    uint ch = (uint) pow(2, key.nbits) - 1;

    // Para cada pixel da imagem
    for(uint i = 0; i < image.step*image.rows; i += inc)
    {
        char m = 0;

        // Recupera o byte do caracter de bits em bits
        for(uint j = i; j < i+inc; j++)
        {
            m <<= key.nbits;
            m |= (data[j] & ch);
        }

        // Se for nulo, interrompe
        if(m == 0)
            break;

        // Escreve o caracter na saída
        text += m;
    }

    // Cria tabela de transposição
    TransTable trans(text, key);

    // Escreve os caracteres no arquivo
    for(uint i = 0; i < trans.div; i++)
        for(uint j = 0; j < KEY_SIZE; j++)
            msg.write(&(trans.table[j][i]), 1);

    for(uint j = 0; j < trans.left; j++)
        msg.write(&(trans.table[j][trans.div]), 1);

}
